package com.yunxiao.cloud.job.util;

import com.yunxiao.cloud.common.exception.BusinessRuntimeException;
import com.yunxiao.cloud.job.entity.ScheduleJob;
import org.quartz.*;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import static com.yunxiao.cloud.common.constant.ExceptionConstant.SYSTEM_JOB_CODE;

/**
 * @description: 定时器工具类
 * @author: yunxiao
 * @date: 2020/1/13 10:34
 * @version: V1.0
 **/
public class ScheduleUtil {

    private static final Logger logger = LoggerFactory.getLogger(ScheduleUtil.class);

    private static final String SCHEDULE_NAME = "yunxiao_";

    private ScheduleUtil() {
        // to do nothing
    }

    /**
     * 触发器 KEY
     *
     * @param jobId
     * @return
     */
    public static TriggerKey getTriggerKey(String jobId) {
        return TriggerKey.triggerKey(SCHEDULE_NAME + jobId);
    }

    /**
     * 定时器 Key
     *
     * @param jobId
     * @return
     */
    public static JobKey getJobKey(String jobId) {
        return JobKey.jobKey(SCHEDULE_NAME + jobId);
    }

    /**
     * 表达式触发器
     *
     * @param scheduler
     * @param jobId
     * @return
     */
    public static CronTrigger getCronTrigger(Scheduler scheduler, String jobId) {
        try {
            return (CronTrigger) scheduler.getTrigger(getTriggerKey(jobId));
        } catch (SchedulerException e) {
            logger.error("getCronTrigger Fail:{0}", e);
            throw new BusinessRuntimeException(SYSTEM_JOB_CODE, "getCronTrigger Fail", e);
        }
    }

    /**
     * 创建定时器
     *
     * @param scheduler
     * @param scheduleJob
     */
    public static void createJob(Scheduler scheduler, ScheduleJob scheduleJob) {
        try {
            JobDetail jobDetail = JobBuilder.newJob(TaskJobLog.class)
                    .withIdentity(getJobKey(scheduleJob.getJobId())).build();
            CronScheduleBuilder scheduleBuilder = CronScheduleBuilder
                    .cronSchedule(scheduleJob.getCronExpression())
                    .withMisfireHandlingInstructionDoNothing();
            CronTrigger trigger = TriggerBuilder.newTrigger()
                    .withIdentity(getTriggerKey(scheduleJob.getJobId()))
                    .withSchedule(scheduleBuilder).build();
            jobDetail.getJobDataMap().put(ScheduleJob.JOB_PARAM_KEY, scheduleJob);
            scheduler.scheduleJob(jobDetail, trigger);
            // 如果该定时器处于暂停状态
            if (scheduleJob.getStatus() == 1) {
                pauseJob(scheduler, scheduleJob.getJobId());
            }
        } catch (Exception e) {
            logger.error("createJob Fail", e);
            throw new BusinessRuntimeException(SYSTEM_JOB_CODE, "createJob Fail", e);
        }
    }

    /**
     * 更新定时任务
     *
     * @param scheduler
     * @param scheduleJob
     */
    public static void updateJob(Scheduler scheduler, ScheduleJob scheduleJob) {
        try {
            // 构建定时器
            TriggerKey triggerKey = getTriggerKey(scheduleJob.getJobId());
            CronScheduleBuilder scheduleBuilder = CronScheduleBuilder
                    .cronSchedule(scheduleJob.getCronExpression())
                    .withMisfireHandlingInstructionDoNothing();
            CronTrigger trigger = getCronTrigger(scheduler, scheduleJob.getJobId())
                    .getTriggerBuilder().withIdentity(triggerKey)
                    .withSchedule(scheduleBuilder).build();
            trigger.getJobDataMap().put(ScheduleJob.JOB_PARAM_KEY, scheduleJob);
            scheduler.rescheduleJob(triggerKey, trigger);
            // 如果该定时器处于暂停状态
            if (scheduleJob.getStatus() == 1) {
                pauseJob(scheduler, scheduleJob.getJobId());
            }
        } catch (SchedulerException e) {
            logger.error("updateJob Fail", e);
            throw new BusinessRuntimeException(SYSTEM_JOB_CODE, "updateJob Fail", e);
        }
    }

    /**
     * 停止定时器
     *
     * @param scheduler
     * @param jobId
     */
    public static void pauseJob(Scheduler scheduler, String jobId) {
        try {
            scheduler.pauseJob(getJobKey(jobId));
        } catch (SchedulerException e) {
            logger.error("pauseJob Fail", e);
            throw new BusinessRuntimeException(SYSTEM_JOB_CODE, "pauseJob Fail", e);
        }
    }

    /**
     * 恢复定时器
     *
     * @param scheduler
     * @param jobId
     */
    public static void resumeJob(Scheduler scheduler, String jobId) {
        try {
            scheduler.resumeJob(getJobKey(jobId));
        } catch (SchedulerException e) {
            logger.error("resumeJob Fail", e);
            throw new BusinessRuntimeException(SYSTEM_JOB_CODE, "resumeJob Fail", e);
        }
    }

    /**
     * 删除定时器
     *
     * @param scheduler
     * @param jobId
     */
    public static void deleteJob(Scheduler scheduler, String jobId) {
        try {
            scheduler.deleteJob(getJobKey(jobId));
        } catch (SchedulerException e) {
            logger.error("deleteJob Fail", e);
            throw new BusinessRuntimeException(SYSTEM_JOB_CODE, "deleteJob Fail", e);
        }
    }

    /**
     * 执行定时器
     *
     * @param scheduler
     * @param scheduleJob
     */
    public static void run(Scheduler scheduler, ScheduleJob scheduleJob) {
        try {
            JobDataMap dataMap = new JobDataMap();
            dataMap.put(ScheduleJob.JOB_PARAM_KEY, scheduleJob);
            scheduler.triggerJob(getJobKey(scheduleJob.getJobId()), dataMap);
        } catch (SchedulerException e) {
            logger.error("run Fail", e);
            throw new BusinessRuntimeException(SYSTEM_JOB_CODE, "run Fail", e);
        }
    }
}
